/*********************IMPORTANT DRAKVUF LICENSE TERMS***********************
 *                                                                         *
 * DRAKVUF (C) 2014-2022 Tamas K Lengyel.                                  *
 * Tamas K Lengyel is hereinafter referred to as the author.               *
 * This program is free software; you may redistribute and/or modify it    *
 * under the terms of the GNU General Public License as published by the   *
 * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE   *
 * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN.  This guarantees your   *
 * right to use, modify, and redistribute this software under certain      *
 * conditions.  If you wish to embed DRAKVUF technology into proprietary   *
 * software, alternative licenses can be acquired from the author.         *
 *                                                                         *
 * Note that the GPL places important restrictions on "derivative works",  *
 * yet it does not provide a detailed definition of that term.  To avoid   *
 * misunderstandings, we interpret that term as broadly as copyright law   *
 * allows.  For example, we consider an application to constitute a        *
 * derivative work for the purpose of this license if it does any of the   *
 * following with any software or content covered by this license          *
 * ("Covered Software"):                                                   *
 *                                                                         *
 * o Integrates source code from Covered Software.                         *
 *                                                                         *
 * o Reads or includes copyrighted data files.                             *
 *                                                                         *
 * o Is designed specifically to execute Covered Software and parse the    *
 * results (as opposed to typical shell or execution-menu apps, which will *
 * execute anything you tell them to).                                     *
 *                                                                         *
 * o Includes Covered Software in a proprietary executable installer.  The *
 * installers produced by InstallShield are an example of this.  Including *
 * DRAKVUF with other software in compressed or archival form does not     *
 * trigger this provision, provided appropriate open source decompression  *
 * or de-archiving software is widely available for no charge.  For the    *
 * purposes of this license, an installer is considered to include Covered *
 * Software even if it actually retrieves a copy of Covered Software from  *
 * another source during runtime (such as by downloading it from the       *
 * Internet).                                                              *
 *                                                                         *
 * o Links (statically or dynamically) to a library which does any of the  *
 * above.                                                                  *
 *                                                                         *
 * o Executes a helper program, module, or script to do any of the above.  *
 *                                                                         *
 * This list is not exclusive, but is meant to clarify our interpretation  *
 * of derived works with some common examples.  Other people may interpret *
 * the plain GPL differently, so we consider this a special exception to   *
 * the GPL that we apply to Covered Software.  Works which meet any of     *
 * these conditions must conform to all of the terms of this license,      *
 * particularly including the GPL Section 3 requirements of providing      *
 * source code and allowing free redistribution of the work as a whole.    *
 *                                                                         *
 * Any redistribution of Covered Software, including any derived works,    *
 * must obey and carry forward all of the terms of this license, including *
 * obeying all GPL rules and restrictions.  For example, source code of    *
 * the whole work must be provided and free redistribution must be         *
 * allowed.  All GPL references to "this License", are to be treated as    *
 * including the terms and conditions of this license text as well.        *
 *                                                                         *
 * Because this license imposes special exceptions to the GPL, Covered     *
 * Work may not be combined (even as part of a larger work) with plain GPL *
 * software.  The terms, conditions, and exceptions of this license must   *
 * be included as well.  This license is incompatible with some other open *
 * source licenses as well.  In some cases we can relicense portions of    *
 * DRAKVUF or grant special permissions to use it in other open source     *
 * software.  Please contact tamas.k.lengyel@gmail.com with any such       *
 * requests.  Similarly, we don't incorporate incompatible open source     *
 * software into Covered Software without special permission from the      *
 * copyright holders.                                                      *
 *                                                                         *
 * If you have any questions about the licensing restrictions on using     *
 * DRAKVUF in other works, are happy to help.  As mentioned above,         *
 * alternative license can be requested from the author to integrate       *
 * DRAKVUF into proprietary applications and appliances.  Please email     *
 * tamas.k.lengyel@gmail.com for further information.                      *
 *                                                                         *
 * If you have received a written license agreement or contract for        *
 * Covered Software stating terms other than these, you may choose to use  *
 * and redistribute Covered Software under those terms instead of these.   *
 *                                                                         *
 * Source is provided to this software because we believe users have a     *
 * right to know exactly what a program is going to do before they run it. *
 * This also allows you to audit the software for security holes.          *
 *                                                                         *
 * Source code also allows you to port DRAKVUF to new platforms, fix bugs, *
 * and add new features.  You are highly encouraged to submit your changes *
 * on https://github.com/tklengyel/drakvuf, or by other methods.           *
 * By sending these changes, it is understood (unless you specify          *
 * otherwise) that you are offering unlimited, non-exclusive right to      *
 * reuse, modify, and relicense the code.  DRAKVUF will always be          *
 * available Open Source, but this is important because the inability to   *
 * relicense code has caused devastating problems for other Free Software  *
 * projects (such as KDE and NASM).                                        *
 * To specify special license conditions of your contributions, just say   *
 * so when you send them.                                                  *
 *                                                                         *
 * This program is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the DRAKVUF   *
 * license file for more details (it's in a COPYING file included with     *
 * DRAKVUF, and also available from                                        *
 * https://github.com/tklengyel/drakvuf/COPYING)                           *
 *                                                                         *
 * This file was created by Jan Gruber.                                    *
 * It is distributed as part of DRAKVUF under the same license             *
 ***************************************************************************/

#ifndef QMP_COMMANDS_H
#define QMP_COMMANDS_H

#include <stdbool.h>
#include <json-c/json.h>

#include "keymap_evdev_to_qapi.h"

/* Constants used as key/values in QMP's JSON */
#define QMP_KEY_EXECUTE "execute"
#define QMP_KEY_ARGUMENTS "arguments"
#define QMP_VAL_SCREENDUMP "screendump"
#define QMP_VAL_FILENAME "filename"
#define QMP_KEY_TYPE "type"
#define QMP_VAL_INPUT_SEND_EVENT "input-send-event"
#define QMP_VAL_ABSOLUTE "abs"
#define QMP_VAL_RELATIVE "rel"
#define QMP_KEY_DATA "data"
#define QMP_KEY_AXIS "axis"
#define QMP_KEY_VALUE "value"
#define QMP_VAL_BTN_TYPE "btn"
#define QMP_KEY_BTN "button"
#define QMP_KEY_DOWN "down"
#define QMP_KEY_KEY "key"
#define QMP_VAL_QCODE "qcode"
#define QMP_VAL_NUMBER "number"
#define QMP_KEY_EVENTS "events"

/* Enum used as mapping for BTN_VALUES */
enum BTN_ENUM
{
    left, middle, right
};

static const char* BTN_VALUES[] =
{
    "left", "middle", "right"
};

/* Enum used as mapping for AXIS_VALUES */
enum AXIS_ENUM
{
    ax_x, ax_y, ax_z
};

static const char* AXIS_VALUES[] =
{
    "x", "y", "z"
};

/*
 * Wraps a given array of json_objects in an input-send-event-command.
 * This funtion creates a json_object, which has the b/m string representation
 * to submit to QMP socket:
 *
 * "{ \"execute\": \"input-send-event\" , \"arguments\": { \"events\":
 * [ ..events.. ]}}"
 */
struct json_object* construct_input_event_cmd(struct json_object* events)
{
    struct json_object* jobj, *arg_obj;

    if (!events)
        return NULL;

    arg_obj = json_object_new_object();
    json_object_object_add(arg_obj, QMP_KEY_EVENTS, events);

    jobj = json_object_new_object();

    json_object_object_add(jobj, QMP_KEY_EXECUTE,
        json_object_new_string(QMP_VAL_INPUT_SEND_EVENT));
    json_object_object_add(jobj, QMP_KEY_ARGUMENTS, arg_obj);

    return jobj;
}

/*
 * Creates a json_object, which resembles a QMP's screendump-command
 *
 * This funtion creates a json_object, which has the b/m string representation
 * to submit to the QMP socket:
 * "{ \"execute\":\"screendump\", \"arguments\": { \"filename\":
 * \"/given/filename\" } }"
 */
struct json_object* construct_screendump_cmd(const char* filename)
{
    struct json_object* jobj, *fn_obj;

    if (!filename)
        return NULL;

    jobj = json_object_new_object();
    json_object_object_add(jobj, QMP_KEY_EXECUTE,
        json_object_new_string(QMP_VAL_SCREENDUMP));

    fn_obj = json_object_new_object();
    json_object_object_add(fn_obj, QMP_VAL_FILENAME,
        json_object_new_string(filename));
    json_object_object_add(jobj, QMP_KEY_ARGUMENTS, fn_obj);

    return jobj;
}

/*
 * Adds a type element ("type": "given_type")to an existing json_object
 */
void add_type(struct json_object* type_obj, const char* type)
{
    if (!type_obj || !type)
        return;

    json_object_object_add(type_obj, QMP_KEY_TYPE, json_object_new_string(type));
}

/*
 * Creates a json_object, which resembles a QMP's command to move the mouse
 * cursor. This funtion creates a json_object, which has the b/m string
 * representation to submit to the QMP socket:
 *
 * " { \"type\": \"%s\", \"data\" : {\"axis\": \"x\", \"value\": %d } },
 * {\"type\": \"%s\", \"data\": { \"axis\": \"y\", \"value\": %d } }"
 */
struct json_object* construct_mouse_move_event(enum AXIS_ENUM ax, bool is_abs,
    int z)
{
    struct json_object* evt_obj, *data_obj;

    evt_obj = json_object_new_object();

    if (is_abs)
        add_type(evt_obj, QMP_VAL_ABSOLUTE);
    else
        add_type(evt_obj, QMP_VAL_RELATIVE);

    /*
     * Constructs an element in the form of
     * "data":  { \"axis\": \"x\", \"value\": %d }
     */
    data_obj = json_object_new_object();
    json_object_object_add(data_obj, QMP_KEY_AXIS,
        json_object_new_string(AXIS_VALUES[ax]));
    json_object_object_add(data_obj, QMP_KEY_VALUE, json_object_new_int(z));
    json_object_object_add(evt_obj, QMP_KEY_DATA, data_obj);

    return evt_obj;
}

/*
 * Creates a json_object, which resembles a QMP's command to press a mouse
 * button. This funtion creates a json_object, which has the b/m string
 * representation to submit to the QMP socket:
 *
 * " { \"type\": \"btn\" , \"data\" : { \"down\": %s, \"button\": \"%s\" } }"
 */
struct json_object* construct_mouse_button_event(enum BTN_ENUM b, bool is_down)
{
    struct json_object* evt_obj, *data_obj;

    evt_obj = json_object_new_object();
    add_type(evt_obj, QMP_VAL_BTN_TYPE);

    /* Constructs "data":  { \"down\": \"%s\", \"button\": %s } */
    data_obj = json_object_new_object();
    json_object_object_add(data_obj, QMP_KEY_DOWN,
        json_object_new_boolean(is_down));
    json_object_object_add(data_obj, QMP_KEY_BTN,
        json_object_new_string(BTN_VALUES[b]));
    json_object_object_add(evt_obj, QMP_KEY_DATA, data_obj);

    return evt_obj;
}

/*
 * Creates a json_object, which resembles a QMP's command to press a key
 *
 * This funtion creates a json_object, which has the b/m string representation
 * to submit to the QMP socket:
 * " { \"type\": \"key\", \"data\" : { \"down\": %s, \"key\": {\"type\":
 * \"qcode\", \"data\": \"%s\" } } } "
 */
struct json_object* construct_qapi_keypress_event(int key, bool is_down)
{
    struct json_object* evt_obj, *data_obj, *key_obj;


    evt_obj = json_object_new_object();
    add_type(evt_obj, QMP_KEY_KEY);

    /* Constructs \"data\" : { \"down\": %s, \"key\": { */
    data_obj = json_object_new_object();
    json_object_object_add(data_obj, QMP_KEY_DOWN,
        json_object_new_boolean(is_down));

    /* Constructs {\"type\": \"qcode\", \"data\": \"%s\" } */
    key_obj = json_object_new_object();

    if ((unsigned int) key < name_map_linux_to_qcode_len)
    {
        add_type(key_obj, QMP_VAL_QCODE);
        json_object_object_add(key_obj, QMP_KEY_DATA,
            json_object_new_string(name_map_linux_to_qcode[key]));
    }
    else
    {
        add_type(key_obj, QMP_VAL_NUMBER);
        json_object_object_add(key_obj, QMP_KEY_DATA, json_object_new_int(key));
    }

    json_object_object_add(data_obj, QMP_KEY_KEY, key_obj);
    json_object_object_add(evt_obj, QMP_KEY_DATA, data_obj);

    return evt_obj;
}

#endif